/*******************************************************************************
 Chatty - Mobile Messaging - J2ME ICQ clone
 Copyright (C) 2003-05  Chatty Project

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 ********************************************************************************
 File: src/chatty/ContactList.java
 Version: ###VERSION###  Date: ###DATE###
 Author(s): Manuel Linsmayer, Andreas Rossbacher, Artyomov Denis
 *******************************************************************************/

package chatty.cl;

import DrawControls.icons.Icon;
import DrawControls.icons.ImageList;
import DrawControls.tree.*;
import DrawControls.*;
import chatty.*;
import chatty.chat.*;
import chatty.chat.message.*;
import chatty.comm.*;
import chatty.forms.*;
import chatty.modules.*;
import chatty.modules.traffic.*;
import chatty.ui.*;
import chatty.ui.base.NativeCanvas;
import chatty.ui.menu.*;
import chatty.util.*;
import java.util.*;
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import protocol.*;
import protocol.simp.*;

public final class ContactList implements TextBoxListener, SelectListener, ContactListListener, PopupListener {
    private final TextListEx aboutTextList = new TextListEx(null);
    private final MenuModel mainMenu = new MenuModel(MenuModel.MENU_LEFT);
	
	
    private MessageEditor editor;
    private Select mainMenuView;
    private VirtualContactList contactList;
    private final StatusView statusView = new StatusView();
    private Contact currentContact;
    private Protocol activeProtocol;
    private InputTextBox passwordTextBox;

    private ContactList() {
    }
    public void initUI() {
        contactList = new VirtualContactList();
        contactList.setCLListener(this);
        mainMenu.setActionListener(this);
        mainMenuView = new Select(mainMenu);
        editor = new MessageEditor();
    }

    public byte getProtocolType(Profile account) {
        for (int i = 0; i < Profile.protocolTypes.length; ++i) {
            if (account.protocolType == Profile.protocolTypes[i]) {
                return account.protocolType;
            }
        }
        return Profile.protocolTypes[0];
    }
    private boolean is(Protocol protocol, Profile profile) {
        if (protocol.getProfile() == profile) {
            return true;
        }
        return (protocol.getProfile().protocolType == profile.protocolType)
                && profile.userId.equals(protocol.getProfile().userId);
    }
    public void addProtocols(Vector accounts) {
        int count = contactList.getModel().getProtocolCount();
        Protocol[] protocols = new Protocol[count];
        for (int i = 0; i < count; ++i) {
            protocols[i] = contactList.getModel().getProtocol(i);
        }
        contactList.getModel().removeAllProtocols();
        for (int i = 0; i < accounts.size(); ++i) {
            Profile profile = (Profile)accounts.elementAt(i);
            for (int j = 0; j < protocols.length; ++j) {
                Protocol protocol = protocols[j];
                if ((null != protocol) && is(protocol, profile)) {
                    if (protocol.getProfile() != profile) {
                        protocol.setProfile(profile);
                    }
                    protocols[j] = null;
                    profile = null;
                    contactList.getModel().addProtocol(protocol);
                    break;
                }
            }
            if (null != profile) {
                addProtocol(profile);
            }
        }
        for (int i = 0; i < protocols.length; ++i) {
            Protocol protocol = protocols[i];
            if (null != protocol) {
                protocol.disconnect();
                protocol.safeSave();
                protocol.dismiss();
            }
        }
    }
    public void initAccounts() {
        int count = Math.max(1, Options.getAccountCount());
        for (int i = 0; i < count; ++i) {
            Profile p = Options.getAccount(i);
            if (p.isActive) {
                addProtocol(p);
            }
        }
    }

    public void addProtocol(Profile account) {
        Protocol protocol = new Simp( getProtocolType(account) );
		
        if (null == protocol) {
            return;
        }
        protocol.setProfile(account);
        protocol.init();
        protocol.safeLoad();
        contactList.getModel().addProtocol(protocol);
    }
    public Protocol getProtocol(Profile profile) {
        int count = contactList.getModel().getProtocolCount();
        for (int i = 0; i < count; ++i) {
            Protocol p = contactList.getModel().getProtocol(i);
            if (null == p) {
                continue;
            }
            if (p.getProfile() == profile) {
                return p;
            }
        }
        return null;
    }

    private static final ContactList instance = new ContactList();
    public static ContactList getInstance() {
        return instance;
    }

    
    private void activate() {
        contactList.update();
        contactList.show();
    }
    public static void activateContactList() {
        instance.activate();
    }
    
    public void startUp() {
        if (0 == Options.getAccountCount()) {
            updateUnreadedMessageCount();
            updateMenu();
            mainMenu.setDefaultItemCode(MENU_STATUS);
            //contactList.show();
            mainMenuView.show(contactList);
            new AccountsForm().showAccountEditor(null);

        } else {
            contactList.show();
            if (Options.getBoolean(Options.OPTION_AUTO_CONNECT)) {
                autoConnect();
            }
        }
    }
    private void autoConnect() {
        getManager().getModel().getProtocol(0).connect();
    }
    public void updateAbout() {
        aboutTextList.initAbout();
    }
    
    public MessageEditor getMessageEditor() {
        return editor;
    }

    /* *********************************************************** */
    final static public int SORT_BY_STATUS = 0;
    final static public int SORT_BY_ONLINE = 1;
    final static public int SORT_BY_NAME   = 2;
    
    /* *********************************************************** */
    //==================================//
    //                                  //
    //    WORKING WITH CONTACTS TREE    //
    //                                  //  
    //==================================//
    public boolean isConnected() {
        int count = contactList.getModel().getProtocolCount();
        for (int i = 0; i < count; ++i) {
            Protocol p = contactList.getModel().getProtocol(i);
            if ((null != p) && p.isConnected()) {
                return true;
            }
        }
        return false;
    }
    public void disconnect() {
        int count = contactList.getModel().getProtocolCount();
        for (int i = 0; i < count; ++i) {
            Protocol p = contactList.getModel().getProtocol(i);
            if ((null != p) && p.isConnected()) {
                p.disconnect();
            }
        }
    }
    public void safeSave() {
        int count = contactList.getModel().getProtocolCount();
        for (int i = 0; i < count; ++i) {
            Protocol p = contactList.getModel().getProtocol(i);
            if (null != p) {
                p.safeSave();
            }
        }
    }

    public void collapseAll() {
        int count = contactList.getModel().getProtocolCount();
        for (int i = 0; i < count; ++i) {
            Protocol p = contactList.getModel().getProtocol(i);
            if (null == p) continue;
            Vector groups = p.getGroupItems();
            for (int groupIndex = 0; groupIndex < groups.size(); ++groupIndex) {
                ((TreeBranch)groups.elementAt(groupIndex)).setExpandFlag(false);
            }
        }
        contactList.setCurrentItem(0);
        contactList.update();
    }
    public VirtualContactList getManager() {
        return contactList;
    }

    private final boolean hasContact(Contact contact) {
        return contact.getProtocol().inContactList(contact);
    }

    
    /**
     * Adds the given message to the message queue of the contact item
     * identified by the given UIN
     */
    public void addMessage(Contact contact, Message message) {
        final boolean isPlainMsg = (message instanceof PlainMessage);
        final boolean isOnlineMsg = !message.isOffline();

        boolean isSingleUser = contact.isSingleUserContact();
        boolean isMultiUserNotify = false;

        boolean isPaused = false;
        // #sijapp cond.if target is "MIDP2" #
        isPaused = Chatty.isPaused() && isCollapsible();
		if (isPaused && isSingleUser && Options.getBoolean(Options.OPTION_BRING_UP)) {
            Chatty.setMinimized(false);
            isPaused = false;
        }
		// #sijapp cond.end #

        // #sijapp cond.if modules_LIGHT is "true" #
        if (isSingleUser || isMultiUserNotify) {
            CustomLight.setLightMode(CustomLight.ACTION_MESSAGE);
        }
        // #sijapp cond.end#

        // #sijapp cond.if modules_SOUND is "true" #
        if (message.isOffline()) {
            // Offline messages don't play sound
            
        } else if (isSingleUser) {
            if (contact.isSingleUserContact()
                    && contact.isAuth() && !contact.isTemp()
                    && message.isWakeUp()) {
                Notify.playSoundNotification(Notify.NOTIFY_ALARM);

            } else {
                Notify.playSoundNotification(Notify.NOTIFY_MESSAGE);
            }
                
            // #sijapp cond.if protocols_JABBER is "true" #
        } else if (isMultiUserNotify) {
            Notify.playSoundNotification(Notify.NOTIFY_MULTIMESSAGE);
            // #sijapp cond.end #
        }
        // #sijapp cond.end#
        if (isPaused || !isSingleUser) {
            return;
        }

        if (Chatty.getCurrentDisplay() == contactList) {
            contactList.setActiveContact(contact);
        }

        if (isPlainMsg && isOnlineMsg) {
            String text = message.getProcessedText();
            if ((4 < text.length()) && text.startsWith(PlainMessage.CMD_ME)) {
                text = message.getName() + " " + text.substring(4);
            }
            String from = contact.getName();
            // #sijapp cond.if protocols_JABBER is "true" #
            if (!contact.isSingleUserContact()) {
                from = message.getName() + "@" + from;
            }
            // #sijapp cond.end #
            contact.showPopupWindow(from, text);
        }
    }

	public final void recivedMessage(Contact contact) {
        // Notify splash canvas
        if (Chatty.isLocked()) {
            SplashCanvas.messageAvailable();
        }
        if (null == VirtualList.getMessageIcon()) {
            updateUnreadedMessageCount();
        }
    }
    public final void markMessages(Contact contact) {
        if (null != VirtualList.getMessageIcon()) {
            updateUnreadedMessageCount();
        }
    }
    private void updateUnreadedMessageCount() {
        Icon icon = null;
        if (0 < getUnreadMessCount()) {
            icon = Message.msgIcons.iconAt(Message.ICON_MSG_NONE);
        }
        if (icon != VirtualList.getMessageIcon()) {
            VirtualList.setMessageIcon(icon);
            chatty.ui.base.NativeCanvas.getInstance().repaint();
        }
    }
 
    

    // #sijapp cond.if modules_SOUND is "true" #
    public final void beginTyping(Contact item, boolean type) {
        // #sijapp cond.if modules_SOUND is "true" #
        if (type && item.getProtocol().isConnected()) {
            Notify.playSoundNotification(Notify.NOTIFY_TYPING);
        }
        // #sijapp cond.end #
        contactList.invalidate();
    }
    // #sijapp cond.end#
        
    public final Contact getCurrentContact() {
        return currentContact;
    }
    public final void setCurrentContact(Contact contact) {
        currentContact = contact;
    }
    public StatusView getStatusView() {
        return statusView;
    }

	/* Static constants for menu actios */
	private static final int MENU_CONNECT    = 1;
	private static final int MENU_DISCONNECT = 2;
	private static final int MENU_OPTIONS    = 3;
	private static final int MENU_TRAFFIC    = 4;
	private static final int MENU_KEYLOCK    = 5;
	private static final int MENU_STATUS     = 6;
	private static final int MENU_XSTATUS    = 7;
	private static final int MENU_PRIVATE_STATUS = 8;
	private static final int MENU_GROUPS     = 9;
    private static final int MENU_SEND_SMS   = 10;
	private static final int MENU_ABOUT      = 11;
	private static final int MENU_MINIMIZE   = 12;
	private static final int MENU_SOUND      = 13;
	private static final int MENU_MYSELF     = 14;
	//private static final int MENU_SERVICES   = 15;
	private static final int MENU_CLIENT     = 15;
    private static final int MENU_DEBUGLOG   = 16;
    private static final int MENU_MAGIC_EYE  = 17;
	private static final int MENU_EXIT       = 18;

    /////////////////////////////////////////////////////////////////
    /** ************************************************************************* */
    public boolean isCollapsible() {
        // #sijapp cond.if target is "MIDP2" #
        return Chatty.isPhone(Chatty.PHONE_SE) || Chatty.isPhone(Chatty.PHONE_NOKIA_S60);
        // #sijapp cond.else #
        return false;
        // #sijapp cond.end #
    }
    private final boolean isSmsSupported() {
        if (activeProtocol.getProfile().protocolType == Profile.PROTOCOL_MRIM) {
            return true;
        }

        // #sijapp cond.if target is "MIDP2"#
        // #sijapp cond.if modules_FILES="true"#
        return !isCollapsible();
        // #sijapp cond.else #
        return false;
        // #sijapp cond.end #
        // #sijapp cond.else #
        return false;
        // #sijapp cond.end #
    }

    
    /* Builds the main menu (visual list) */
    public void activateMainMenu() {
        updateMenu();
        mainMenu.setDefaultItemCode(MENU_STATUS);
        mainMenuView.show();
    }

    public void protocolMenu(MenuModel mainMenu, Protocol protocol) {
		activeProtocol = protocol;
        if (protocol.isConnecting()) {
            mainMenu.addItem("disconnect", Chatty.menuIcons.iconAt(Chatty.ICON_DISCONNECT),  MENU_DISCONNECT);
            return;
        }
        if (protocol.isConnected()) {
            mainMenu.addItem("disconnect", Chatty.menuIcons.iconAt(Chatty.ICON_CONNECT),  MENU_DISCONNECT);
            
        } else {
            mainMenu.addItem("connect", Chatty.menuIcons.iconAt(Chatty.ICON_CONNECT),  MENU_CONNECT);
        }
        mainMenu.addItem("set_status", protocol.getStatusInfo().getIcon(protocol.getStatus()),  MENU_STATUS);
        // #sijapp cond.if modules_XSTATUSES is "true" #
        mainMenu.addItem("set_xstatus", ((Simp)protocol).getXStatus().getIcon(), MENU_XSTATUS);
        // #sijapp cond.end #
        mainMenu.addItem("private_status", PrivateStatusForm.getIcon(protocol), MENU_PRIVATE_STATUS);
   
        if (protocol.isConnected()) {
            mainMenu.addItem("manage_contact_list", Chatty.menuIcons.iconAt(Chatty.ICON_GROUPS), MENU_GROUPS);
            mainMenu.addItem("myself", Chatty.menuIcons.iconAt(Chatty.ICON_MYSELF), MENU_MYSELF);
			//mainMenu.addItem("services", Chatty.menuIcons.iconAt(Chatty.ICON_SERVICES), MENU_SERVICES);
           
        }
        if (isSmsSupported()) {
            mainMenu.addItem("send_sms", Chatty.menuIcons.iconAt(Chatty.ICON_SEND_SMS), MENU_SEND_SMS);
        }

    }
    protected void updateMenu() {
        int currentCommand = mainMenuView.getSelectedItemCode();
        mainMenu.clean();
        mainMenu.addItem("keylock_enable", Chatty.menuIcons.iconAt(Chatty.ICON_KEYLOCK), MENU_KEYLOCK);
        if (0 < getManager().getModel().getProtocolCount()) {
            protocolMenu(mainMenu, getManager().getCurrentProtocol());
        }
        mainMenu.addItem("options_lng", Chatty.menuIcons.iconAt(Chatty.ICON_OPTIONS), MENU_OPTIONS);
        
        // #sijapp cond.if modules_SOUND is "true" #
		boolean isSilent = Options.getBoolean(Options.OPTION_SILENT_MODE);
		if( isSilent ) {
			mainMenu.addItem("#sound_on", Chatty.menuIcons.iconAt(Chatty.ICON_SOUND_ON), MENU_SOUND);
        } else {
			mainMenu.addItem("#sound_off", Chatty.menuIcons.iconAt(Chatty.ICON_SOUND_OFF),  MENU_SOUND);
	    }
		// #sijapp cond.end#
        

		
        // #sijapp cond.if modules_DEBUGLOG is "true" #
        mainMenu.addItem("debug log", MENU_DEBUGLOG);
        // #sijapp cond.end#
        // #sijapp cond.if modules_MAGIC_EYE is "true" #
        mainMenu.addItem("magic eye", Chatty.menuIcons.iconAt(Chatty.ICON_MAGIC_EYE), MENU_MAGIC_EYE);
        // #sijapp cond.end#
        // #sijapp cond.if modules_TRAFFIC is "true" #
        mainMenu.addItem("traffic_lng", Chatty.menuIcons.iconAt(Chatty.ICON_TRAFFIC), MENU_TRAFFIC);
		
        // #sijapp cond.end#
        mainMenu.addItem("about", Chatty.menuIcons.iconAt(Chatty.ICON_ABOUT), MENU_ABOUT);
		
        // #sijapp cond.if target is "MIDP2" #
        if (isCollapsible()) {
            mainMenu.addItem("minimize", Chatty.menuIcons.iconAt(Chatty.ICON_MINIMIZE), MENU_MINIMIZE);
        }
        // #sijapp cond.end#
        mainMenu.addItem("exit", Chatty.menuIcons.iconAt(Chatty.ICON_EXIT), MENU_EXIT);

        mainMenu.setDefaultItemCode(currentCommand);
        mainMenuView.setModel(mainMenu);
        mainMenuView.invalidate();
    }

    /* Activates the main menu */
    public static void updateMainMenu() {
        instance.updateMenu();
    }

    public int getUnreadMessCount() {
        int count = 0;
        for (int i = 0; i < contactList.getModel().getProtocolCount(); ++i) {
            Protocol p = contactList.getModel().getProtocol(i);
            if (null != p) {
                count += p.getUnreadMessCount();
            }
        }
        return count;
    }
    private void doExit(boolean anyway) {
        NativeCanvas.stopKeyRepeating();
        if (!anyway && (0 < getUnreadMessCount())) {
            PopupWindow.showAttentionBox(ResBundle.getString("have_unread_mess"), this);
        } else {
            Chatty.getChatty().quit();
        }
    }
    
    /* Command listener */
    public void textboxAction(InputTextBox box, boolean ok) {
        if ((box == passwordTextBox) && ok) {
            final Protocol protocol = activeProtocol;
            protocol.setPassword(passwordTextBox.getString());
            passwordTextBox.back();
            if (!StringConvertor.isEmpty(protocol.getPassword())) { 
                protocol.connect();
            }
        }
    }
    public void popupAction() {
        doExit(true);
    }

    private void execCommand(int cmd) {
        final Protocol proto = activeProtocol;
        switch (cmd) {
            case MENU_CONNECT:
                if (proto.isEmpty()) {
                    new AccountsForm().showAccountEditor(proto.getProfile());

                } else if (StringConvertor.isEmpty(proto.getPassword())) {
                    passwordTextBox = new InputTextBox("password", 32, TextField.PASSWORD);
                    passwordTextBox.setTextBoxListener(this);
                    passwordTextBox.show();

                } else {
                    contactList.restore();
                    proto.connect();
                }
                break;

            case MENU_DISCONNECT:
                proto.disconnect();
                Thread.yield();
                /* Show the main menu */
                ContactList.activateContactList();
                break;

            case MENU_KEYLOCK:
                Chatty.lockChatty();
                break;

            case MENU_STATUS:
                new SomeStatusForm(proto, SomeStatusForm.SF_STATUS_LIST).show();
                break;

                // #sijapp cond.if modules_XSTATUSES is "true" #
            case MENU_XSTATUS:
                new XStatusForm((Simp)proto).show();
                break;

                // #sijapp cond.if modules_SERVERLISTS is "true" #
            case MENU_PRIVATE_STATUS:
                new PrivateStatusForm(proto).show();
                break;
                // #sijapp cond.end #
                
            case MENU_OPTIONS:
                OptionsForm.activate();
                break;

                // #sijapp cond.if modules_TRAFFIC is "true" #
            case MENU_TRAFFIC:
                new TrafficScreen().show();
                break;
                // #sijapp cond.end #

            case MENU_ABOUT:
                updateAbout();
                aboutTextList.show();
                break;

            case MENU_GROUPS:
                new ManageContactListForm(proto).show();
                break;

                // #sijapp cond.if target is "MIDP2"#
            case MENU_MINIMIZE:
                /* Minimize Chatty (if supported) */
                contactList.restore();
                Chatty.setMinimized(true);
                break;
                // #sijapp cond.end#

            // #sijapp cond.if modules_DEBUGLOG is "true" #
            case MENU_DEBUGLOG:
                DebugLog.activate();
                break;
            // #sijapp cond.end#

            // #sijapp cond.if modules_MAGIC_EYE is "true" #
            case MENU_MAGIC_EYE:
                MagicEye.activate();
                break;
            // #sijapp cond.end#
                
            // #sijapp cond.if modules_SOUND is "true" #
            case MENU_SOUND:
                Notify.changeSoundMode(false);
                updateMenu();
                break;
            // #sijapp cond.end#
                
            case MENU_MYSELF:
                proto.createTempContact(proto.getUserId(), proto.getNick()).showUserInfo();
                break;
            //case MENU_SERVICES:
                //proto.createTempContact(proto.getUserId(), proto.getNick()).showUserInfo();
               // break;
				
            case MENU_SEND_SMS:
                if (isSmsSupported()) {
                    new SmsForm(proto, null).show();
                }
                break;

            case MENU_EXIT:
                doExit(false);
                break;
        }
    }
    public void select(Select select, MenuModel model, int cmd) {
        execCommand(cmd);
    }
}